﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace SPHelper
{
	public class Address
	{
		public string[] BeginningAddressLines { get; set; }
		public string Street1 { get; set; }
		public string Street2 { get; set; }
		public string Street3 { get; set; }
		public string City { get; set; }
		public string StateCode { get; set; }
		public string Zip { get; set; }
		public string Zip4 { get; set; }
		public string CountryCode { get; set; }

		
		/// <summary>
		/// Format Address
		/// </summary>
		/// <param name="street1"></param>
		/// <param name="street2"></param>
		/// <param name="street3"></param>
		/// <param name="city"></param>
		/// <param name="state"></param>
		/// <param name="zip"></param>
		/// <param name="zip4"></param>
		/// <param name="countryCode"></param>
		/// <param name="delim"></param>
		/// <param name="beginningAddressLines"></param>
		/// <returns></returns>
		public static string FormatAddress(string street1, string street2, string street3, string city, 
			string stateCode, string zip, string zip4, string countryCode, string delim, params string[] beginningAddressLines)
		{
			string o = null;
			
			
			// beginning address lines (come before the street lines)
			if (beginningAddressLines != null && beginningAddressLines.Length > 0)
			{
				foreach (string line in beginningAddressLines) 
				{
					if (!string.IsNullOrEmpty(line))
					{
						o += line + delim;
					}
				}
			}

			// street
			if (!String.IsNullOrEmpty(street1)) { o += street1 + delim; }
			if (!String.IsNullOrEmpty(street2)) { o += street2 + delim; }
			if (!String.IsNullOrEmpty(street3)) { o += street3 + delim; }

			// city & state
			if (!String.IsNullOrEmpty(city)) { o += city; }
			if (!string.IsNullOrEmpty(city) && !string.IsNullOrEmpty(stateCode)) { o += ", "; }
			if (!String.IsNullOrEmpty(stateCode)) { o += stateCode; }

			// zip
			if (!String.IsNullOrEmpty(zip))
			{
				o += " " + zip;
				if (!String.IsNullOrEmpty(zip4)) { o += "-" + zip4; }
			}

			// country
			if (!String.IsNullOrEmpty(countryCode) && (countryCode != "USA" || string.IsNullOrEmpty(o)))
			{
				// show country only if NOT USA (unless rest of address is blank)
				if (!string.IsNullOrEmpty(o) && o.Length > 5 && o.Substring(o.Length - delim.Length, delim.Length) != delim)
				{
					o += delim;
				}
				string countryFullname = Countries[countryCode];
				if (string.IsNullOrEmpty(countryFullname)) { countryFullname = countryCode; }	// this is an error, country fullname should have been pulled
				o += countryFullname;
			}

			return o;
		}

		/// <summary>
		/// Format address object into string
		/// </summary>
		/// <param name="adr"></param>
		/// <param name="delim"></param>
		/// <returns></returns>
		public static string FormatAddress(Address adr, string delim)
		{
			string o = null;
			if (adr != null)
			{
				o = FormatAddress(adr.Street1, adr.Street2, adr.Street3, adr.City, adr.StateCode, adr.Zip, adr.Zip4,
					adr.CountryCode, delim, adr.BeginningAddressLines);
			}
			return o;
		}

		/// <summary>
		/// Parse Full Zip Code to get the zip and zip4 separated.
		/// i.e., user enters: 22209-1234
		/// returns 22209 AND 1234
		/// Does not do validation, you must do that yourself later
		/// </summary>
		/// <param name="zip"></param>
		/// <param name="zip4"></param>
		/// <param name="errorMessage"></param>
		public static void ParseZip(ref string zip, ref string zip4, ref string errorMessage)
		{
			try
			{
				// parse zip for zip4
				if (!string.IsNullOrEmpty(zip) && string.IsNullOrEmpty(zip4))
				{
					string[] delimiters = new string[] { "-", " " };
					string delim = null;
					for (int i = 0; i < delimiters.Length; i++)
					{
						if (zip.Contains(delimiters[i])) { delim = delimiters[i]; break; }
					}
					if (!string.IsNullOrEmpty(delim))
					{
						// delimiter found, now parse for zip4 based on it
						zip4 = zip.Substring(zip.IndexOf(delim) + 1, zip.Length - zip.IndexOf(delim) - 1);
						zip = zip.Substring(0, zip.IndexOf(delim));
					}
				}
			}
			catch (Exception ex)
			{
				Log.WriteError("dsgrdfuGGtdr", ex);
				errorMessage = ex.Message;
			}
		}

		/// <summary>
		/// Determine if passed address is complete enough to ship to
		/// </summary>
		/// <param name="adr"></param>
		/// <param name="errorMessage"></param>
		/// <returns></returns>
		public static bool IsValidAddress(string street1, string street2, string street3, string city,
			string stateCode, string zip, string zip4, string countryCode, bool isZip4Required, ref string errorMessage)
		{
			bool isValid = true;
			try
			{
				// init 
				if (string.IsNullOrEmpty(countryCode)) { countryCode = "USA"; }

				// usa or canada
				if (countryCode == "USA" || countryCode == "CAN")
				{
					// zip
					if (string.IsNullOrEmpty(zip)) { throw new Exception("Zip code is required"); }
					if (countryCode == "USA")
					{
						if (!Regex.Match(zip, @"^\d{5}$").Success) { throw new Exception("Zip code must be 5 digits"); }
						if (isZip4Required && string.IsNullOrEmpty(zip4)) { throw new Exception("Zip+4 is required for an organization address"); }
						if (!string.IsNullOrEmpty(zip4))
						{
							if (!Regex.Match(zip4, @"^\d{4}$").Success) { throw new Exception("Zip4 code must be 4 digits"); }
						}
					}

					//state
					if (string.IsNullOrEmpty(stateCode)) { throw new Exception("State is required"); }
					if (stateCode.Length != 2) { throw new Exception("Invalid state code: " + stateCode); }

					// city
					if (string.IsNullOrEmpty(city)) { throw new Exception("City is required"); }
					if (city.Length < 3) { throw new Exception("City must be at least 2 characters"); }

					// street
					if (string.IsNullOrEmpty(street1)) { throw new Exception("Street is required"); }
					if (street1.Length < 3) { throw new Exception("Street Line 1 must be at least 2 characters"); }
				}
				else
				{
					// foreign country
					if (countryCode.Length != 3) { throw new Exception("Country code must be 3 characters: " + countryCode); }

					// city
					if (string.IsNullOrEmpty(city)) { throw new Exception("City is required"); }
					if (city.Length < 3) { throw new Exception("City must be at least 2 characters"); }

					// street
					if (string.IsNullOrEmpty(street1)) { throw new Exception("Street Line 1 is required"); }
					if (street1.Length < 3) { throw new Exception("Street Line 1 must be at least 2 characters"); }
				}
			}
			catch (Exception ex)
			{
				errorMessage = ex.Message;
				isValid = false;
			}
			return isValid;
		}

		/// <summary>
		/// Determine if passed Address object is valid
		/// </summary>
		/// <param name="adr"></param>
		/// <param name="isZip4Required"></param>
		/// <param name="errorMessage"></param>
		/// <returns></returns>
		public static bool IsValidAddress(Address adr, bool isZip4Required, ref string errorMessage)
		{
			bool isValid = true;
			try
			{
				// init 
				if (adr == null) { throw new Exception("Address Passed is Null or Empty"); }

				isValid = IsValidAddress(adr.Street1, adr.Street2, adr.Street3, adr.City, adr.StateCode,
					adr.Zip, adr.Zip4, adr.CountryCode, isZip4Required, ref errorMessage);
			}
			catch (Exception ex)
			{
				errorMessage = ex.Message;
				isValid = false;
			}
			return isValid;
		}


		


		/// <summary>
		/// Dictionary of states and their codes
		/// </summary>
		public static Dictionary<string, string> States
		{
			get
			{
				Dictionary<string, string> _states = new Dictionary<string, string>();
				_states.Add("AA", "Armed Forces (AA)");
				_states.Add("AA", "Armed Forces (AA)");
				_states.Add("AB", "Alberta");
				_states.Add("AE", "Armed Forces (AE)");
				_states.Add("AK", "Alaska");
				_states.Add("AL", "Alabama");
				_states.Add("AP", "Armed Forces (AP)");
				_states.Add("AR", "Arkansas");
				_states.Add("AS", "American Samoa");
				_states.Add("AZ", "Arizona");
				_states.Add("BC", "British Columbia");
				_states.Add("CA", "California");
				_states.Add("CO", "Colorado");
				_states.Add("CT", "Connecticut");
				_states.Add("DC", "District of Columbia");
				_states.Add("DE", "Delaware");
				_states.Add("FL", "Florida");
				_states.Add("FM", "Micronesia");
				_states.Add("GA", "Georgia");
				_states.Add("GU", "Guam");
				_states.Add("HI", "Hawaii");
				_states.Add("IA", "Iowa");
				_states.Add("ID", "Idaho");
				_states.Add("IL", "Illinois");
				_states.Add("IN", "Indiana");
				_states.Add("KS", "Kansas");
				_states.Add("KY", "Kentucky");
				_states.Add("LA", "Louisiana");
				_states.Add("MA", "Massachusetts");
				_states.Add("MB", "Manitoba");
				_states.Add("MD", "Maryland");
				_states.Add("ME", "Maine");
				_states.Add("MH", "Marshall islands");
				_states.Add("MI", "Michigan");
				_states.Add("MN", "Minnesota");
				_states.Add("MO", "Missouri");
				_states.Add("MP", "Mariana Islands");
				_states.Add("MS", "Mississippi");
				_states.Add("MT", "Montana");
				_states.Add("NB", "New Brunswick");
				_states.Add("NC", "North Carolina");
				_states.Add("ND", "North Dakota");
				_states.Add("NE", "Nebraska");
				_states.Add("NH", "New Hampshire");
				_states.Add("NJ", "New Jersey");
				_states.Add("NL", "Newfoundland and Labrador");
				_states.Add("NM", "New Mexico");
				_states.Add("NS", "Nova Scotia");
				_states.Add("NT", "Northwest Territories");
				_states.Add("NU", "Nunavut");
				_states.Add("NV", "Nevada");
				_states.Add("NY", "New York");
				_states.Add("OH", "Ohio");
				_states.Add("OK", "Oklahoma");
				_states.Add("ON", "Ontario");
				_states.Add("OR", "Oregon");
				_states.Add("PA", "Pennsylvania");
				_states.Add("PE", "Prince Edward Island");
				_states.Add("PR", "Puerto Rico");
				_states.Add("PW", "Palau");
				_states.Add("QC", "Quebec");
				_states.Add("RI", "Rhode Island");
				_states.Add("SC", "South Carolina");
				_states.Add("SD", "South Dakota");
				_states.Add("SK", "Saskatchewan");
				_states.Add("TN", "Tennessee");
				_states.Add("TX", "Texas");
				_states.Add("UT", "Utah");
				_states.Add("VA", "Virginia");
				_states.Add("VI", "Virgin Islands");
				_states.Add("VT", "Vermont");
				_states.Add("WA", "Washington");
				_states.Add("WI", "Wisconsin");
				_states.Add("WV", "West Virginia");
				_states.Add("WY", "Wyoming");
				_states.Add("YT", "Yukon");
				return _states;
			}
		}

		/// <summary>
		/// Dictionary of countries and their 3 letter code
		/// </summary>
		public static Dictionary<string, string> Countries
		{
			get
			{
				Dictionary<string, string> _countries = new Dictionary<string, string>();
				_countries.Add("ALG", "Algeria");
				_countries.Add("ARE", "United Arab Emirates");
				_countries.Add("ARG", "Argentina");
				_countries.Add("ARM", "Armenia");
				_countries.Add("ATG", "Antigua and Barbuda");
				_countries.Add("AUS", "Australia");
				_countries.Add("AUT", "Austria");
				_countries.Add("AZE", "Azerbaijan");
				_countries.Add("BDI", "Burundi");
				_countries.Add("BEL", "Belgium");
				_countries.Add("BEN", "Benin");
				_countries.Add("BFA", "Burkina Faso");
				_countries.Add("BGD", "Bangladesh");
				_countries.Add("BGR", "Bulgaria");
				_countries.Add("BHR", "Bahrain");
				_countries.Add("BHS", "Bahamas");
				_countries.Add("BIH", "Bosnia, Herzegovina");
				_countries.Add("BLR", "Belarus");
				_countries.Add("BLZ", "Belize");
				_countries.Add("BMU", "Bermuda");
				_countries.Add("BOL", "Bolivia");
				_countries.Add("BRA", "Brazil");
				_countries.Add("BRB", "Barbados");
				_countries.Add("BRN", "Brunei Darussalam");
				_countries.Add("BTN", "Bhutan");
				_countries.Add("BWA", "Botswana");
				_countries.Add("CAF", "Central African Republic");
				_countries.Add("CAN", "Canada");
				_countries.Add("CCK", "Cocos Islands");
				_countries.Add("CHE", "Switzerland");
				_countries.Add("CHL", "Chile");
				_countries.Add("CHN", "China");
				_countries.Add("CIV", "Cote D'Ivoire");
				_countries.Add("CMR", "Cameroon");
				_countries.Add("COG", "Congo");
				_countries.Add("COL", "Colombia");
				_countries.Add("COM", "Comoros");
				_countries.Add("CPV", "Cape Verde");
				_countries.Add("CRI", "Costa Rica");
				_countries.Add("CUB", "Cuba");
				_countries.Add("CXR", "Christmas Island");
				_countries.Add("CYM", "Cayman Islands");
				_countries.Add("CYP", "Cyprus");
				_countries.Add("CZE", "Czech Republic");
				_countries.Add("DEU", "Germany");
				_countries.Add("DJI", "Djibouti");
				_countries.Add("DMA", "Dominica");
				_countries.Add("DNK", "Denmark");
				_countries.Add("DOM", "Dominican Republic");
				_countries.Add("ECU", "Ecuador");
				_countries.Add("EGY", "Egypt");
				_countries.Add("ERI", "Eritrea");
				_countries.Add("ESH", "Western Sahara");
				_countries.Add("ESP", "Spain");
				_countries.Add("EST", "Estonia");
				_countries.Add("ETH", "Ethiopia");
				_countries.Add("FIN", "Finland");
				_countries.Add("FJI", "Fiji");
				_countries.Add("FRA", "France");
				_countries.Add("FSM", "Micronesia");
				_countries.Add("GAB", "Gabon");
				_countries.Add("GBR", "United Kingdom");
				_countries.Add("GEO", "Georgia");
				_countries.Add("GHA", "Ghana");
				_countries.Add("GIB", "Gibraltar");
				_countries.Add("GIN", "Guinea");
				_countries.Add("GLP", "Guadaloupe");
				_countries.Add("GMB", "Gambia");
				_countries.Add("GNB", "Guinea-Bissau");
				_countries.Add("GNQ", "Equatorial Guinea");
				_countries.Add("GRC", "Greece");
				_countries.Add("GRD", "Grenada");
				_countries.Add("GRL", "Greenland");
				_countries.Add("GTM", "Guatemala");
				_countries.Add("GUF", "Guiana");
				_countries.Add("GUM", "Guam");
				_countries.Add("GUY", "Guyana");
				_countries.Add("HKG", "Hong Kong");
				_countries.Add("HND", "Honduras");
				_countries.Add("HRV", "Hrvatska");
				_countries.Add("HTI", "Haiti");
				_countries.Add("HUN", "Hungary");
				_countries.Add("IDN", "Indonesia");
				_countries.Add("IND", "India");
				_countries.Add("IRL", "Ireland");
				_countries.Add("IRN", "Iran");
				_countries.Add("IRQ", "Iraq");
				_countries.Add("ISL", "Iceland");
				_countries.Add("ISR", "Israel");
				_countries.Add("ITA", "Italy");
				_countries.Add("JAM", "Jamaica");
				_countries.Add("JOR", "Jordan");
				_countries.Add("JPN", "Japan");
				_countries.Add("KAZ", "Kazakhstan");
				_countries.Add("KEN", "Kenya");
				_countries.Add("KGZ", "Kyrgyz Republic");
				_countries.Add("KHM", "Cambodia");
				_countries.Add("KIR", "Kiribati");
				_countries.Add("KOR", "South Korea");
				_countries.Add("KWT", "Kuwait");
				_countries.Add("LAO", "Laos");
				_countries.Add("LBN", "Lebanon");
				_countries.Add("LBR", "Liberia");
				_countries.Add("LBY", "Libya");
				_countries.Add("LIE", "Liechtenstein");
				_countries.Add("LKA", "Sri Lanka");
				_countries.Add("LSO", "Lesotho");
				_countries.Add("LTU", "Lithuania");
				_countries.Add("LUX", "Luxembourg");
				_countries.Add("LVA", "Latvia");
				_countries.Add("MAC", "Macao");
				_countries.Add("MAR", "Morocco");
				_countries.Add("MCO", "Monaco");
				_countries.Add("MDA", "Moldova");
				_countries.Add("MDG", "Madagascar");
				_countries.Add("MDV", "Maldives");
				_countries.Add("MEX", "Mexico");
				_countries.Add("MKD", "Macedonia");
				_countries.Add("MLI", "Mali");
				_countries.Add("MLT", "Malta");
				_countries.Add("MMR", "Myanmar");
				_countries.Add("MNG", "Mongolia");
				_countries.Add("MOZ", "Mozambique");
				_countries.Add("MRT", "Mauritania");
				_countries.Add("MSR", "Montserrat");
				_countries.Add("MTQ", "Martinique");
				_countries.Add("MUS", "Mauritius");
				_countries.Add("MWI", "Malawi");
				_countries.Add("MYS", "Malaysia");
				_countries.Add("MYT", "Mayotte");
				_countries.Add("NAM", "Namibia");
				_countries.Add("NCL", "New Caledonia");
				_countries.Add("NER", "Niger");
				_countries.Add("NFK", "Norfolk Island");
				_countries.Add("NGA", "Nigeria");
				_countries.Add("NIC", "Nicaragua");
				_countries.Add("NIU", "Niue");
				_countries.Add("NLD", "Netherlands");
				_countries.Add("NOR", "Norway");
				_countries.Add("NPL", "Nepal");
				_countries.Add("NRU", "Nauru");
				_countries.Add("NZL", "New Zealand");
				_countries.Add("OMN", "Oman");
				_countries.Add("PAK", "Pakistan");
				_countries.Add("PAN", "Panama");
				_countries.Add("PER", "Peru");
				_countries.Add("PHL", "Philippines");
				_countries.Add("PLW", "Palau");
				_countries.Add("PNG", "Papua New Guinea");
				_countries.Add("POL", "Poland");
				_countries.Add("PRI", "Puerto Rico");
				_countries.Add("PRK", "North Korea");
				_countries.Add("PRT", "Portugal");
				_countries.Add("PRY", "Paraguay");
				_countries.Add("PSE", "Palestinian Territory");
				_countries.Add("PYF", "French Polynesia");
				_countries.Add("QAT", "Qatar");
				_countries.Add("REU", "Reunion");
				_countries.Add("ROU", "Romania");
				_countries.Add("RUS", "Russia");
				_countries.Add("RWA", "Rwanda");
				_countries.Add("SAU", "Saudi Arabia");
				_countries.Add("SCG", "Serbia and Montenegro");
				_countries.Add("SDN", "Sudan");
				_countries.Add("SEN", "Senegal");
				_countries.Add("SGP", "Singapore");
				_countries.Add("SGS", "South Georgia");
				_countries.Add("SLB", "Solomon Islands");
				_countries.Add("SLE", "Sierra Leone");
				_countries.Add("SLV", "El Salvador");
				_countries.Add("SMR", "San Marino");
				_countries.Add("SOM", "Somalia");
				_countries.Add("SUR", "Suriname");
				_countries.Add("SVK", "Slovakia");
				_countries.Add("SVN", "Slovenia");
				_countries.Add("SWE", "Sweden");
				_countries.Add("SWZ", "Swaziland");
				_countries.Add("SYC", "Seychelles");
				_countries.Add("SYR", "Syria");
				_countries.Add("TCD", "Chad");
				_countries.Add("TGO", "Togo");
				_countries.Add("THA", "Thailand");
				_countries.Add("TJK", "Tajikistan");
				_countries.Add("TKL", "Tokelau");
				_countries.Add("TKM", "Turkmenistan");
				_countries.Add("TLS", "Timor-Leste");
				_countries.Add("TON", "Tonga");
				_countries.Add("TTO", "Trinidad and Tobago");
				_countries.Add("TUN", "Tunisia");
				_countries.Add("TUR", "Turkey");
				_countries.Add("TUV", "Tuvalu");
				_countries.Add("TWN", "Taiwan");
				_countries.Add("TZA", "Tanzania");
				_countries.Add("UGA", "Uganda");
				_countries.Add("UKR", "Ukraine");
				_countries.Add("URY", "Uruguay");
				_countries.Add("USA", "United States of America");
				_countries.Add("UZB", "Uzbekistan");
				_countries.Add("VAT", "Holy See");
				_countries.Add("VEN", "Venezuela");
				_countries.Add("VGB", "British Virgin Islands");
				_countries.Add("VIR", "US Virgin Islands");
				_countries.Add("VNM", "Viet Nam");
				_countries.Add("VUT", "Vanuatu");
				_countries.Add("WSM", "Samoa");
				_countries.Add("YEM", "Yemen");
				_countries.Add("ZAF", "South Africa");
				_countries.Add("ZMB", "Zambia");
				_countries.Add("ZWE", "Zimbabwe");

				return _countries;
			}

		}

	}
}
